#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include "funcutil.h"

namespace wb {


static char* sprintf_n(char* buf, char* last, uint64_t num, char zero, uintptr_t hex, uintptr_t width);

char* slprintf(char* buf, char* last, const char* fmt, ...)
{
    va_list args;
    char*   p;
    va_start(args, fmt);
    p = vslprintf(buf, last, fmt, args);
    va_end(args);
    return p;
}

char* snprintf(char* buf, size_t maxSize, const char* fmt, ...)
{
    va_list args;
    char*   p;
    va_start(args, fmt);
    p = vslprintf(buf, buf + maxSize, fmt, args);
    va_end(args);
    return p;
}

char* vslprintf(char* buf, char* last, const char* fmt, va_list args)
{
    char zero;
    uintptr_t width, sign, hex, frac_width, scale, n;
    int64_t i64;
    uint64_t ui64;
    char* p;
    double f;
    uint64_t frac;

    while (*fmt && buf < last)
    {
        if (*fmt == '%')
        {
            zero = (*++fmt == '0' ? '0' : ' ');
            width = 0;
            sign = 1;
            hex = 0;
            frac_width = 0;
            i64 = 0;
            ui64 = 0;

            while (*fmt >= '0' && *fmt <= '9')
            {
                width = width * 10 + (*fmt - '0');
            }

            for (;;)
            {
                switch (*fmt)
                {
                case 'u':
                    sign = 0;
                    fmt++;
                    continue;
                case 'X':
                    hex = 2;
                    sign = 0;
                    fmt++;
                    continue;
                case 'x':
                    hex = 1;
                    sign = 0;
                    fmt++;
                    continue;

                case '.':
                    fmt++;
                    while (*fmt >= '0' && *fmt <= '9')
                    {
                        frac_width = frac_width * 10 + (*fmt++ - '0');
                    }
                    break;
                default:
                    break;
                } //end switch
                break;
            } //end for(;;)
            switch (*fmt)
            {
            case '%':
                *buf++ = '%';
                fmt++;
                continue;
            case 'd':
                if (sign)
                {
                    i64 = (int64_t) va_arg(args, int);
                }
                else
                {
                    ui64 = (uint64_t) va_arg(args, uint64_t);
                }
                break;
            case 'i':
                if (sign)
                {
                    i64 = (int64_t) va_arg(args, uintptr_t);
                }
                else
                {
                    ui64 = (uint64_t) va_arg(args, uintptr_t);
                }
                break;
            case 'L':
                if (sign)
                {
                    i64 = va_arg(args, int64_t);
                }
                else
                {
                    ui64 = va_arg(args, uint64_t);
                }
                break;
            case 'p':
                ui64 = (uintptr_t) va_arg(args, void *);
                hex = 2;
                sign = 0;
                zero = '0';
                width = 2 * sizeof(void *);
                break;
            case 's':
                p = va_arg(args, char*);
                while (*p && buf < last)
                {
                    *buf++ = *p++;
                }
                fmt++;
                continue;
            case 'P':
                i64 = (int64_t) va_arg(args, pid_t);
                sign = 1;
                break;
            case 'f':
                f = va_arg(args, double);
                if (f < 0)
                {
                    *buf++ = '-';
                    f = -f;
                }

                ui64 = (int64_t) f;
                frac = 0;

                if (frac_width)
                {
                    scale = 1;
                    for (n = frac_width; n; --n)
                    {
                        scale *= 10;
                    }

                    frac = (uint64_t)((f - (double)ui64) * scale + 0.5);

                    if (frac == scale)
                    {
                        ui64++;
                        frac = 0;
                    }
                } //end if (frac_width)
                buf = sprintf_n(buf, last, ui64, zero, 0, width);
                if (frac_width)
                {
                    if (buf < last)
                    {
                        *buf++ = '.';
                    }
                    buf = sprintf_n(buf, last, frac, '0', 0, frac_width);
                }
                fmt++;
                continue;
            default:
                *buf++ = *fmt++;
                continue;
            } // end switch

            //到这里的都是%d的
            if (sign)
            {
                if (i64 < 0)
                {
                    *buf++ = '-';
                    ui64 = (uint64_t) -i64;
                }
                else
                {
                    ui64 = (uint64_t) i64;
                }
            } //end if(sign)

            buf = sprintf_n(buf, last, ui64, zero, hex, width);
            fmt++;
        }
        else  //当做普通字符处理
        {
            *buf++ = *fmt++;
        } //end if (*fmt == %)
    } //end outer while

    return buf;
}

static char* sprintf_n(char* buf, char* last, uint64_t num, char zero, uintptr_t hex, uintptr_t width)
{
    char* p, temp[21];
    size_t len;
    uint32_t ui32;
    static char hexc[] = "0123456789abcdef";
    static char HEXC[] = "0123456789ABCDEF";

    p = temp + 20;  //最后一个位置

    if (hex == 0)
    {
        if (num <= (uint64_t) UINT32_MAX)
        {
            ui32 = (uint32_t) num;
            do {
                *--p = (char) (ui32 % 10 + '0');
            } while (ui32 /= 10);
        }
        else
        {
            do {
                *--p = (char) (num % 10 + '0');
            } while (num /= 10);
        }
    }
    else if (hex == 1)
    {
        do {
            *--p = hexc[(uint32_t)(num & 0xf)];
        } while (num >>= 4); //每次右移4位
    }
    else
    {
        do {
            *--p = HEXC[(uint32_t)(num & 0xf)];
        } while (num >>= 4);
    }

    len = (temp + 20) - p;

    while (len++ < width && buf < last) //填充0
    {
        *buf++ = zero;
    }

    len = (temp + 20) - p;

    if (buf + len >= last)
    {
        len = last - buf;
    }

    return (char*)(memcpy(buf, p, len) + len);

}

void rtrim(char* cstr)
{
    size_t len = 0;
    if (cstr == nullptr)
    {
        return ;
    }
    len = strlen(cstr) - 1;
    while (len > 0 && cstr[len] == ' ') cstr[len--] = 0;
    return ;
}

void ltrim(char* cstr)
{
    size_t len = strlen(cstr);
    char* p = cstr;
    if (*p != ' ') return ;
    while (*p == ' ') p++;

    if (*p == 0) { //循环到非空格发现是结束符，则退出
        *cstr = 0;
        return ;
    }

    char* q = cstr;
    while (*p) *p++ = *q++; //从后面往前面复制，消除前导空格
    *q = 0;
    return ;
}


} //namespace wb